﻿//***********************************************************************
// Assembly         : phpmk
// Author           : sy
// Created          : 06-14-2010
//
// Last Modified By : sy
// Last Modified On : 06-15-2010
// Description      : 
//
// Copyright        : (c) Another-D-Mention Software. All rights reserved.
//***********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using phpmk.ADM.Out;
using phpmk.ADM.Core.Model;
using System.Xml;
using System.Reflection;

namespace phpmk.ADM.Core.Configuration
{
    class ConfigFile
    {
        private static ConfigFile instance;
        private XmlDocument xmlDoc;
        
        public string ConfigurationFile = "";
        public bool Loaded/* = false*/;
        public DataModel Model;

        public ConfigFile()
        {
            Loaded = false;
            String currentDirectory = Directory.GetCurrentDirectory();
            while (true) {
                if (File.Exists(currentDirectory + "\\" + Constants.ConfigFile)) {
                    ConfigurationFile = currentDirectory + "\\" + Constants.ConfigFile;
                    break;
                } else {
                    currentDirectory = currentDirectory.Substring(0, currentDirectory.LastIndexOf("\\", StringComparison.CurrentCulture));
                    if (currentDirectory.EndsWith(":", StringComparison.CurrentCulture)) {
                        break;
                    }
                }
            }
            Load();
            instance = this;
        }

        public void Load()  {
            if (String.IsNullOrEmpty(ConfigurationFile)) {
                return;
            }
            Model = new DataModel();
            xmlDoc = new XmlDocument();
            try {
                xmlDoc.Load(ConfigurationFile);
            } catch (XmlException ex) {
                throw new Exception(ex.Message + " \n\nPlease use -validate command.");
            }

            DeserializeObject(Model, "//");

            Loaded = true;
        }

        private void DeserializeObject(Object Obj, String parentnode)
        {
            Configurable Attr;
            foreach (FieldInfo Field in Obj.GetType().GetFields()) {
                foreach (Attribute attr in Field.GetCustomAttributes(false)) {
                    Attr = attr as Configurable;
                    if (null != Attr) {
                        string fieldName = Field.Name.Substring(0, 1).ToLower() + Field.Name.Substring(1);
                        string tagName = (parentnode != "//" ? parentnode + "/" : parentnode) + (Attr.IsAttribute ? "@" : "") + fieldName;
                        XmlNode node;
                        if (Attr.IsAttribute) {
                            Field.SetValue(Obj, xmlDoc.SelectSingleNode(tagName).InnerText);
                            continue;
                        }
                        if (Field.FieldType.Name == "String") {
                            node = xmlDoc.SelectSingleNode(tagName);
                            if (node == null) {
                                Field.SetValue(Obj, Attr.DefaultValue);
                            } else {
                                Field.SetValue(Obj, node.InnerText);
                            }
                        } else {
                            if (Field.FieldType.IsSubclassOf(typeof(Array))) {
                                XmlNodeList list;
                                string nodename = Field.Name.Substring(0, 1).ToLower() + Field.Name.Substring(1);
                                FieldInfo[] fields = ((Array)Field.GetValue(Obj)).GetValue(0).GetType().GetFields();
                                if (fields.Length == 1) {
                                    nodename = fields[0].Name.Substring(0, 1).ToLower() + fields[0].Name.Substring(1);
                                    list = xmlDoc.SelectNodes(tagName + "/" + nodename);
                                } else {
                                    list = xmlDoc.SelectNodes(tagName);
                                }
                                if (list != null) {
                                    int count = list.Count;
                                    Type currentType = ((Array)Field.GetValue(Obj)).GetValue(0).GetType();
                                    Field.SetValue(Obj, System.Activator.CreateInstance(Field.FieldType, count));
                                    int i = 0;
                                    Array reff = (Array)Field.GetValue(Obj);
                                    foreach (XmlNode item in list) {
                                        reff.SetValue(System.Activator.CreateInstance(currentType), i);
                                        if (fields.Length == 1) {
                                            Object obj = reff.GetValue(i);
                                            if (obj != null) {
                                                FieldInfo f = obj.GetType().GetField(fields[0].Name);
                                                if (f != null) {
                                                    f.SetValue(reff.GetValue(i), item.InnerText);
                                                }
                                            }
                                        } else {
                                            DeserializeObject(reff.GetValue(i), tagName + "[" + (i + 1).ToString() + "]");
                                        }
                                        i++;
                                    }
                                }
                            } else {
                                DeserializeObject(Field.GetValue(Obj), tagName);
                            }
                        }
                    }
                }
            }
        }

        public static ConfigFile GetInstance() {
            if (instance == null) {
                instance = new ConfigFile();
            }
            return instance;
        }
    }
}
